﻿using System;
using NUnit.Framework;
using Rhino.Mocks;
using System.Linq;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace NMA.Infrastructure.NHibernate.Tests.Facade
{
    using NMA.Domain.Model.Repository;
    using NMA.Infrastructure.NHibernate.Service.Event;
    using NMA.Infrastructure.EventAggregator;
    using NMA.Application;
    using NMA.Domain.Shared;
    using NMA.Domain.Model;
    using NMA.Infrastructure.NHibernate.DomainObject;
    using NMA.Domain.Model.Service.Application;
    using NMA.Domain.Model.DTO;
    using NMA.Domain.Shared.Paging;
    using NMA.Infrastructure.NHibernate.Paging;
    using NMA.Infrastructure.NHibernate.CriteriaExpression;
    using NMA.Infrastructure.NHibernate.OrderByExpression;

    [TestFixture]
    public class CategoryFacadeTest : TestingBase
    {
        private ICategoryRepository _categoryRepository = null;
        private IConsumer<AuditEvent> _handler = null;
        private ICategoryFacade _categoryFacade = null;
        private IDomainObjectFactory _objectfactory = null;
        private IAuditFactory _auditFactory = null;
        private ICriteriaExpressionFactory _searchExpressionFactory = null;
        private IOrderByExpressionFactory _orderByExpressionFactory = null;

        protected override void Before_each_test()
        {
            base.Before_each_test();

            _categoryRepository = MockRepository.GenerateMock<ICategoryRepository>();
            _handler = MockRepository.GenerateMock<IConsumer<AuditEvent>>();            
            _objectfactory = new DomainObjectFactory();
            _auditFactory = MockRepository.GenerateMock<IAuditFactory>();
            _searchExpressionFactory = MockRepository.GenerateMock<ICriteriaExpressionFactory>();
            _orderByExpressionFactory = MockRepository.GenerateMock<IOrderByExpressionFactory>();
            _categoryFacade = new CategoryFacade(_categoryRepository, _handler, _auditFactory, _searchExpressionFactory, _orderByExpressionFactory);
        }

        [Test]
        public void Can_call_get_all_category_method()
        {
            // Arrange
            IList<ICategory> list = new List<ICategory>()
            {
                new Category()
                {
                     Id = Guid.NewGuid(),
                     Name = "test category",
                     CreatedUser  ="testuser",
                     UpdatedUser="testuser",
                     CreatedDate=DateTime.Now,
                     UpdatedDate=DateTime.Now
                }
            };

            AuditEvent eventArgs = new AuditEvent()
            {
                UserAction = "get all category",
                UserName = "testusername",
                DateEvent = DateTime.Now
            };

            _categoryRepository.Expect(x => x.All()).Return(list);
            _handler.Expect(x => x.Handle(null)).IgnoreArguments();
            _auditFactory.Expect(x => x.CreateGetAllCategoryEvent(null)).IgnoreArguments().Return(eventArgs);
            // Act
            var result = _categoryFacade.All();
            //Assert
            _handler.VerifyAllExpectations();
            Assert.IsNotNull(result);
            Assert.GreaterOrEqual(result.Count(), 0);
        }

        [Test]
        public void Can_call_count_all_category_method()
        {
            // Arrange
            _categoryRepository.Expect(x => x.CountAllCategory()).Return(10);
            // Act
            var result = _categoryFacade.CountAllCategory();
            //Assert
            Assert.GreaterOrEqual(result, 10);
        }

        [Test]
        public void Can_call_get_by_id_method()
        { 
            // Arrange
            var category = _objectfactory.CreateCategory("test name", "testinguser", "");
            _categoryRepository.Expect(x => x.GetById(Arg<Guid>.Is.Anything)).Return(category);
            // Act
            var dto = _categoryFacade.GetById(Guid.NewGuid());
            // Assert
            Assert.AreNotSame(category, dto);
            Assert.IsTrue(string.Compare(category.Name, dto.Name) == 0);
            Assert.IsTrue(string.Compare(category.CreatedUser, dto.CreatedUser) == 0);
        }

        [Test]
        public void Can_call_add_method()
        {
            // Arrange
            var dto = new CategoryDTO()
            {
                Id = Guid.NewGuid(),
                Name = "category name",
                CreatedUser = "testuser",
                UpdatedUser = "testuser",
                CreatedDate = DateTime.Now,
                UpdatedDate = DateTime.Now
            };
            var id = Guid.NewGuid();
            _categoryRepository.Expect(x => x.Add(Arg<ICategory>.Is.Anything)).Return(id);
            // Act
            var result = _categoryFacade.Add(dto);
            // Assert
            Assert.IsNotNull(result);
            Assert.IsTrue(result == id);
        }

        [Test]
        public void Can_call_remove_method()
        { 
            // Arrange
            var dto = new CategoryDTO()
            {
                Id = Guid.NewGuid(),
                Name = "category name",
                CreatedUser = "testuser",
                UpdatedUser = "testuser",
                CreatedDate = DateTime.Now,
                UpdatedDate = DateTime.Now
            };
            _categoryRepository.Expect(x => x.Remove(Arg<ICategory>.Is.Anything));
            // Act
            _categoryFacade.Remove(dto);
            //Assert 
            _categoryRepository.VerifyAllExpectations();
        }

        [Test]
        public void Can_call_remove_with_id_method()
        { 
            // Arrange
            _categoryRepository.Expect(x => x.Remove(Arg<Guid>.Is.Anything));
            // Act
            _categoryFacade.Remove(Guid.NewGuid());
            // Assert
            _categoryRepository.VerifyAllExpectations();
        }

        [Test]
        public void Can_call_update_method()
        { 
            // Arrange
            var dto = new CategoryDTO()
            {
                Id = Guid.NewGuid(),
                Name = "category name",
                CreatedUser = "testuser",
                UpdatedUser = "testuser",
                CreatedDate = DateTime.Now,
                UpdatedDate = DateTime.Now
            };
            _categoryRepository.Expect(x => x.Update(Arg<ICategory>.Is.Anything));
            // Act
            _categoryFacade.Update(dto);
            // Assert
            _categoryRepository.VerifyAllExpectations();
        }

        [Test]
        public void Can_call_get_by_method()
        {
            // Arrange
            IEnumerable<ICategory> list = new List<ICategory>() { new Category() {
                 Id = Guid.NewGuid(),
                 Name="name",
                 CreatedUser="user",
                 UpdatedUser="user",
                 CreatedDate=DateTime.Now,
                 UpdatedDate=DateTime.Now,
                 News = null
            }};
            _categoryRepository.Stub(c => c.GetBy(Arg<Expression<Func<ICategory, bool>>>.Is.NotNull)).Return(list);
            // Act
            var result = _categoryFacade.GetBy(x => x.Name == "name", typeof(INameEntity<ICategory>));
            // Assert
            Assert.IsNotNull(result);
        }

        [Test]
        public void Can_call_get_all_category_with_paging_method()
        {
            // Arrange
            IPagedList<ICategory> list = new PagedList<ICategory>()
            {
                new Category()
                {
                     Id = Guid.NewGuid(),
                     Name = "test category",
                     CreatedUser  ="testuser",
                     UpdatedUser="testuser",
                     CreatedDate=DateTime.Now,
                     UpdatedDate=DateTime.Now
                }
            };            

            _categoryRepository.Expect(x => x.All(1, 10)).Return(list);
            // Act
            var result = _categoryFacade.All(1, 10);
            //Assert
            _handler.VerifyAllExpectations();
            Assert.IsNotNull(result);
            Assert.GreaterOrEqual(result.TotalCount, 1);
        }

        [Test]
        public void Can_call_get_all_category_with_paging_lambda_method()
        {
            // Arrange
            CategoryFacade categoryFacade = new CategoryFacade(
                new NMA.Infrastructure.NHibernate.Repository.CategoryRepository(),
                _handler, 
                _auditFactory, 
                new CriteriaExpressionFactory(), 
                new OrderByExpressionFactory());

            NMA.Domain.Model.Contract.CategorySearchCriteria model = new NMA.Domain.Model.Contract.CategorySearchCriteria()
            {
                Id = CategoryList[0].Id,
                Name = CategoryList[0].Name,
                CreatedUser = "",
                CreatedDate = CategoryList[0].CreatedDate
            };

            string orderBy = "Name";
            // Act
            var result = categoryFacade.All(1, 10, model, orderBy, true);
            //Assert
            Assert.IsNotNull(result);
        }

        protected override void After_each_test()
        {
            base.After_each_test();

            if (_categoryRepository != null)
                GC.SuppressFinalize(_categoryRepository);
            if (_handler != null)
                GC.SuppressFinalize(_handler);
            if (_categoryFacade != null)
                GC.SuppressFinalize(_categoryFacade);
            if (_objectfactory != null)
                GC.SuppressFinalize(_objectfactory);
        }
    }
}
